#!/bin/bash

# DarkNebular´s Advanced Wrapper
# Fork from code of BenjaminPoncet rev.12 with some revisions and little fixes and improvements.
rev="AME_12.4.3"
# Changes:
# VS_12.1: Initial release and changed some logging options and variables names for better understand. Fix the offline transcoding. (Deprecated)
# AME_12.1.1: Changed from using VideoStation´s ffmpeg to Advance Media Extensions one. Change the buffering from 1024 to 8192k. Fix the problem with thumbnails are empty and some other little fixes. (Deprecated)
# AME_12.2.1: Initial release for DSM 7.0. Compatible with the new paths of this DSM. Fix the order and the use of the binaries. Added some missing variables in the wrapper and improvements. (Deprecated, migrate to 12.2.2)
# AME_12.2.2: Now with 2 audio streamS for DSM 7.0 (One in MP3 Stereo and other with 5.1 AAC). Chromecast Supported. (Deprecated, migrate to 12.2.3)
# AME_12.2.3: Now the audio's codecs are independent between VideoStation and Media Station. Clean the wrapper code. (Deprecated, migrate to 12.2.4)
# AME_12.2.4: Logging options when all is derived to Community's ffmpeg. Prioritize the use of native ffmpeg in Video Station.
# AME_12.3.1: Initial release for DSM 7.1. Compatible with the new paths of this DSM. (Deprecated, migrate to 12.3.2)
# AME_12.3.2: Now you will have always AAC 5.1 512kbps in DS-Video (mobile), Web-Browsers and Apple-TV. This version is NOT supported for Chromecast streaming. (Deprecated, migrate to 12.3.3)
# AME_12.3.3: Now you will can select between two audio streams in clients in the case that the wrapper needs to recode from DTS, EAC3, TrueHD. One in MP3 Stereo and other with 5.1 AAC. Fix the Chromecast Support. (Deprecated, migrate to 12.3.4)
# AME_12.3.4: Now the audio's codecs are independent between VideoStation and Media Station. Clean the wrapper code. (Deprecated, migrate to 12.3.5)
# AME_12.3.5: Logging options when all is derived to Community's ffmpeg. Prioritize the use of native ffmpeg in Video Station. (Deprecated, migrate to 12.3.6)
# AME_12.3.6: Adding a new pipe in arguments used by the DLNA server in the new versions of Media Server. (Deprecated, migrate to 12.3.7)
# AME_12.3.7: Fixed a bug in Offline Transcoding. (Deprecated, migrate to 12.3.8)
# AME_12.3.8: Improved the viewing of logs. Improved DLNA processing to use only one binary. Fixed a problem to close the process. Fixed a piping problem with the new versions of FFMPEG. (Deprecated, migrate to 12.3.9)
# AME_12.3.9: Improved the removing of the stderr's temporals to specific PID. Fixed a bug with AVBR movies using DLNA transcoding. I remove the buffer 8M for DLNA. It must be only for ChromeCast or Browsers. (Deprecated, migrate to 12.4.1)
# AME_12.4.1: Added support for FFMPEG 6.X binaries and deprecate the use of FFMPEG 4.X. (Deprecated, migrate to 12.4.2)
# AME_12.4.2: Fixed a bug when the movies has HEVC 4K HDR 10bits plus TrueHD 7.1 audio's codec. (Deprecated, migrate to 12.4.3)
# AME_12.4.3: Added a new error code for the new DSM Versions, now this can be controlled.


WHITE="\u001B[37m"
RED="\u001b[31m"
BLUE="\u001b[36m"
PURPLE="\u001B[35m"
GREEN="\u001b[32m"
YELLOW="\u001b[33m"

_log(){
        echo -e "${WHITE}$(date '+%Y-%m-%d %H:%M:%S') - ${streamid} - $1" >> /tmp/wrapper_ffmpeg.log
}

_log_para(){
        echo -e "${WHITE}$1" | fold -w 120 | sed "s/^.*$/$(date '+%Y-%m-%d %H:%M:%S') - ${streamid} -          = &/" >> /tmp/wrapper_ffmpeg.log
}
function newline() {
  echo "" >> /tmp/wrapper_ffmpeg.log
}
_term(){
        rm -f /tmp/ffmpeg-${streamid}.stderr
        _log "${PURPLE}*** KILLCHILD ***"
        kill -TERM "$childpid" 2>/dev/null
}

trap _term SIGTERM

arch=`uname -a | sed 's/.*synology_//' | cut -d '_' -f 1`
nas=`uname -a | sed 's/.*synology_//' | cut -d '_' -f 2`
pid=$$
paramvs=$@
stream="${@: -1}"
streamid="FFM$pid"
bin1=/var/packages/CodecPack/target/pack/bin/ffmpeg41.orig
bin2=/var/packages/ffmpeg6/target/bin/ffmpeg
args=()

vcodec="KO"

while [[ $# -gt 0 ]]
do
case "$1" in
        -i)
                shift
                movie="$1"
                args+=("-i" "$1")
        ;;
        -hwaccel)
                shift
                hwaccel="$1"
                args+=("-hwaccel" "$1")
        ;;
        -scodec)
                shift
                scodec="$1"
                args+=("-scodec" "$1")
        ;;
        -f)
                shift
                fcodec="$1"
                args+=("-f" "$1")
        ;;
        -y)
                shift
                y="$1"
                yoff="OffEnable"
                args+=("-y" "$1")
        ;;
        pipe:4)
        shift
        pipe="pipe_MS"
        args+=("pipe:4")
        ;;
        pipe:6)
        shift
        pipe="pipe_MS"
        args+=("pipe:6")
        ;;
        -map)
                shift
                args+=("-map" "$1")
                idmap=`echo $1 | cut -d : -f 2`
                if [ "$vcodec" = "KO" ]; then
                        vcodec=`/var/packages/ffmpeg6/target/bin/ffprobe -v error -select_streams $idmap -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$movie" | head -n 1`
                        vcodecprofile=`/var/packages/ffmpeg6/target/bin/ffprobe -v error -select_streams $idmap -show_entries stream=profile -of default=noprint_wrappers=1:nokey=1 "$movie" | head -n 1`
                else
                        acodec=`/var/packages/ffmpeg6/target/bin/ffprobe -v error -select_streams $idmap -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$movie" | head -n 1`
                fi
        ;;
        *)
                args+=("$1")
        ;;
esac
shift
done

_log "${PURPLE}*** PROCESS START REV $rev DS$nas ($arch) PID $pid ***"

_log "${PURPLE}MOVIE    = $movie"

set -- "${args[@]}"

argsnew=()
args1vs=()
args2vs=()
args2vsms=()


while [[ $# -gt 0 ]]
do
case "$1" in
        -ss)
                shift
                argsnew+=("-ss" "$1")
                args1vs+=("-ss" "$1")
                args1vs+=("-noaccurate_seek")
		if [ "$vcodec" = "hevc" ] && [ "$acodec" = "truehd" ]; then
		   args2vs+=("-ss" "$1")
		fi
                args2vs+=("-analyzeduration" "10000000")
		args2vsms+=("-ss" "$1")
        ;;
        -i)
                shift
                argsnew+=("-i" "$1")
                args1vs+=("-i" "$1")
		if [ "$vcodec" = "hevc" ] && [ "$acodec" = "truehd" ]; then
		  args2vs+=("-i" "$1" "-map" "0:0" "-map" "0:1" "-map" "0:1")
		else
                  args2vs+=("-i" "pipe:" "-map" "0:0" "-map" "0:1" "-map" "0:1")
		fi
                args2vsms+=("-i" "$1" "-map" "0:0" "-map" "0:1" "-map" "0:1")
        ;;
        -r)
                shift
                argsnew+=()
        ;;
        -vf)
                shift
                if [ "$hwaccel" = "vaapi" ] && [ "$vcodecprofile" = "Main 10" ]; then
                        scale_w=`echo "${1}" | sed -e 's/.*=w=//g' | sed -e 's/:h=.*//g'`
                        scale_h=`echo "${1}" | sed -e 's/.*:h=//g'`
                        if let ${scale_w} AND let ${scale_h}; then
                                argsnew+=("-vf" "scale_vaapi=w=${scale_w}:h=${scale_h}:format=nv12,hwupload,setsar=sar=1")
                        else
                                argsnew+=("-vf" "scale_vaapi=format=nv12,hwupload,setsar=sar=1")
                        fi
                else
                        argsnew+=("-vf" "$1")
                fi
                args1vs+=("-vf" "$1")
		if [ "$vcodec" = "hevc" ] && [ "$acodec" = "truehd" ]; then
                  args2vs+=("-vf" "$1")
		fi
                args2vsms+=("-vf" "$1")
        ;;
        # Para activar los límites de Bitrate que trae el VideoStation. Si se quieren fijar siempre a un valor, cambiar el $1 y poner 8M por ejemplo.
        -vb)
                shift
                argsnew+=("-vb" "$1")
                args1vs+=("-vb" "$1")
                args2vs+=("-vb" "$1")
                args2vsms+=("-vb" "$1")
        ;;
        -vcodec)
                shift
                argsnew+=("-vcodec" "$1")
                args1vs+=("-vcodec" "$1")
		if [ "$vcodec" = "hevc" ] && [ "$acodec" = "truehd" ]; then
		   args2vs+=("-vcodec" "$1")
		else
                  args2vs+=("-vcodec" "copy")
		fi
                args2vsms+=("-vcodec" "$1")
        ;;
        -vsync)
                shift
                argsnew+=("-vsync" "$1")
                args1vs+=("-vsync" "$1")
		if [ "$vcodec" = "hevc" ] && [ "$acodec" = "truehd" ]; then
                  args2vs+=()
		else
                  args2vs+=("-vsync" "$1")
		fi
                args2vsms+=("-vsync" "$1")
        ;;
        # En caso de necesitar hacer decoder de DTS,TrueHD o E-AC3 se convertirá a AAC Surround 5.1 Y MP3 Stereo
        -acodec)
                shift
                if [ "$1" = "libfaac" ]; then
                        argsnew+=("-acodec" "aac")
                        args2vs+=("-acodec" "aac")
                        args2vsms+=("-acodec" "aac")
                else
                        argsnew+=("-acodec" "libfdk_aac")
                        args2vs+=("-c:a:0" "$1" "-c:a:1" "libfdk_aac")
                        args2vsms+=("-c:a:0" "libfdk_aac" "-c:a:1" "$1")

                fi
                args1vs+=("-acodec" "copy")

        ;;
        # En caso de necesitar hacer decoder de DTS,TrueHD o E-AC3 se usará bitrate constante a 512k para AAC y 256k para MP3 Stereo
        -ab)
                shift
                argsnew+=("-b:a" "512k")
                args2vs+=("-b:a:0" "256k" "-b:a:1" "512k")
                args2vsms+=("-b:a:0" "512k" "-b:a:1" "256k")

        ;;
        # Si tienes un Chromecast, debería enviarse en 2 canales. Para ello se mandan dos stream de audio (MP3 y AAC) de la misma pista de audio, siendo el primero a elegir la pista de Stereo MP3.
        # Excepto en el caso de necesitar también re-codificar el video además del audio, para evitar un uso alto de CPU se ha dejado solamente en 2 canales para aumentar la compatibilidad.
        -ac)
                shift
                argsnew+=("-ac" "$1")
                args2vs+=("-ac:1" "$1" "-ac:2" "6")
                args2vsms+=("-ac:1" "6" "-ac:2" "$1")

        ;;
        -f)
                shift
                argsnew+=("-f" "$1")
                args1vs+=("-f" "mpegts")
                args2vs+=("-f" "$1")
                args2vsms+=("-f" "$1")
        ;;
        -segment_format)
                shift
                argsnew+=("-segment_format" "$1")
                args2vs+=("-segment_format" "$1")
                args2vsms+=("-segment_format" "$1")
        ;;
        -segment_list_type)
                shift
                argsnew+=("-segment_list_type" "$1")
                args2vs+=("-segment_list_type" "$1")
                args2vsms+=("-segment_list_type" "$1")
        ;;
        -hls_seek_time)
                shift
                argsnew+=("-hls_seek_time" "$1")
                args2vs+=("-hls_seek_time" "$1")
                args2vsms+=("-hls_seek_time" "$1")
        ;;
        -segment_time)
                shift
                argsnew+=("-segment_time" "$1")
                args2vs+=("-segment_time" "$1")
                args2vsms+=("-segment_time" "$1")
        ;;
        -segment_time_delta)
                shift
                argsnew+=("-segment_time_delta" "$1")
                args2vs+=("-segment_time_delta" "$1")
                args2vsms+=("-segment_time_delta" "$1")
        ;;
        -segment_start_number)
                shift
                argsnew+=("-segment_start_number" "$1")
                args2vs+=("-segment_start_number" "$1")
                args2vsms+=("-segment_start_number" "$1")
        ;;
        -individual_header_trailer)
                shift
                argsnew+=("-individual_header_trailer" "$1")
                args2vs+=("-individual_header_trailer" "$1")
                args2vsms+=("-individual_header_trailer" "$1")
        ;;
        -avoid_negative_ts)
                shift
                argsnew+=("-avoid_negative_ts" "$1")
                args2vs+=("-avoid_negative_ts" "$1")
                args2vsms+=("-avoid_negative_ts" "$1")
        ;;
        -break_non_keyframes)
                shift
                argsnew+=("-break_non_keyframes" "$1")
                args2vs+=("-break_non_keyframes" "$1")
                args2vsms+=("-break_non_keyframes" "$1")
        ;;
        -max_muxing_queue_size)
                shift
                args2vs+=("-max_muxing_queue_size" "$1")
                args2vsms+=("-max_muxing_queue_size" "$1")
        ;;
        -map)
                shift
                argsnew+=("-map" "$1")
                args1vs+=("-map" "$1")

        ;;
        *)
                argsnew+=("$1")
		  if [ "$stream" = "$1" ] && [ "$vcodec" = "hevc" ] && [ "$acodec" = "truehd" ]; then
		     args1vs+=("-bufsize" "8192k" "$1")
		  else
                  	if [ "$stream" = "$1" ]; then
                    	args1vs+=("-bufsize" "8192k" "pipe:")
                  	else
                    	args1vs+=("$1")
                  	fi
		  fi
                args2vs+=("$1")
                args2vsms+=("$1")
        ;;
esac
shift
done

sed -i -e "s/{\"PID\":${pid},\"hardware_transcode\":true,/{\"PID\":${pid},\"hardware_transcode\":false,/" /tmp/VideoStation/enabled

startexectime=`date +%s`

if [ "$yoff" = "OffEnable" ]; then
        _log "${BLUE}VCODEC   = $vcodec ($vcodecprofile)"
        _log "${BLUE}ACODEC   = $acodec"
        _log "${BLUE}PARAM_ORIG  =${WHITE}"
        _log_para "$paramvs"
        _log "${YELLOW}MODE     = MP4_TRANSCO-VS"
        _log "${BLUE}FFMPEG   = $bin2"
        _log "${GREEN}PARAM_WRAP  =${WHITE}"
        param1=${args[@]}
        _log_para "$param1"

        $bin2 "${args[@]}" 2> /tmp/ffmpeg-${streamid}.stderr &

childpid=$!
_log "${BLUE}CHILDPID = $childpid"
wait $childpid
_log "${PURPLE}*** CHILD END ***"
_log "${PURPLE}*** PROCESS END ***"
newline
newline
rm -f /tmp/ffmpeg-${streamid}.stderr
exit 0

fi

if [ "$scodec" = "subrip" ]; then

        _log "${BLUE}FFMPEG   = $bin1"
        _log "${BLUE}CODEC    = $scodec"
        _log "${BLUE}PARAM_ORIG  =${WHITE}"
        _log_para "$paramvs"

        $bin1 "${args[@]}" 2> /tmp/ffmpeg-${streamid}.stderr &

elif [ "$fcodec" = "mjpeg" ]; then

        _log "FFMPEG   = $bin1"
        _log "CODEC    = $fcodec"
        _log "${BLUE}PARAM_ORIG  =${WHITE}"
        _log_para "$paramvs"

        $bin1 "${args[@]}" 2> /tmp/ffmpeg-${streamid}.stderr &

else

        _log "${BLUE}VCODEC   = $vcodec ($vcodecprofile)"
        _log "${BLUE}ACODEC   = $acodec"
        _log "${BLUE}PARAM_ORIG  =${WHITE}"
        _log_para "$paramvs"
        _log "${YELLOW}MODE     = ORIG-VSMS"
        _log "${BLUE}FFMPEG   = $bin1"
        _log "${GREEN}PARAM_WRAP  =${WHITE}"
        param1=${args[@]}
        _log_para "$param1"

        $bin1 "${args[@]}" 2> /tmp/ffmpeg-${streamid}.stderr &

fi

childpid=$!
_log "${BLUE}CHILDPID = $childpid"
wait $childpid

if grep "not found for input stream" /tmp/ffmpeg-${streamid}.stderr || grep "Unknown encoder" /tmp/ffmpeg-${streamid}.stderr || grep "Error opening filters!" /tmp/ffmpeg-${streamid}.stderr || grep "Unrecognized option" /tmp/ffmpeg-${streamid}.stderr || grep "Invalid data found when processing input" /tmp/ffmpeg-${streamid}.stderr && [ "$pipe" = "pipe_MS" ]; then

    _log "${BLUE}*** CHILD END ***"
    startexectime=`date +%s`
    _log "${BLUE}STDOUT   =${WHITE}"
    _log_para "`tail -n 18 /tmp/ffmpeg-${streamid}.stderr`"
    _log "${YELLOW}MODE     = VIDEO-AUDIO_WRAPER-MS"
    _log "${BLUE}FFMPEG1  = $bin2"
    _log "${GREEN}PARAM_WRAP   =${WHITE}"
    param1=${args2vsms[@]}
    _log_para "$param1"


    $bin2 "${args2vsms[@]}" 2> /tmp/ffmpeg-${streamid}.stderr &

    childpid=$!
    _log "${BLUE}CHILDPID = $childpid"
    wait $childpid
    _log "${PURPLE}*** CHILD END ***"
    _log "${PURPLE}*** PROCESS END ***"
    newline
    newline

    rm -f /tmp/ffmpeg-${streamid}.stderr
    exit 0

fi

if grep "Conversion failed!" /tmp/ffmpeg-${streamid}.stderr || grep "Unknown encoder" /tmp/ffmpeg-${streamid}.stderr || grep "not found for input stream" /tmp/ffmpeg-${streamid}.stderr || grep "Error opening filters!" /tmp/ffmpeg-${streamid}.stderr || grep "Unrecognized option" /tmp/ffmpeg-${streamid}.stderr || grep "Invalid data found when processing input" /tmp/ffmpeg-${streamid}.stderr && ! grep "Error writing trailer of pipe:" /tmp/ffmpeg-${streamid}.stderr; then

        _log "${BLUE}*** CHILD END ***"
        startexectime=`date +%s`
        _log "${BLUE}STDOUT   =${WHITE}"
        _log_para "`tail -n 18 /tmp/ffmpeg-${streamid}.stderr`"
        # _log_para "`cat /tmp/ffmpeg-${streamid}.stderr`"
        _log "${YELLOW}MODE     = PIPE V_ORIG-A_WRAP-VS"
        _log "${BLUE}FFMPEG1  = $bin1"
        _log "${BLUE}FFMPEG2  = $bin2"
        _log "${GREEN}PARAM_WRAP1   =${WHITE}"
        param1=${args1vs[@]}
        _log_para "$param1"
        _log "${GREEN}PARAM_WRAP2   =${WHITE}"
        param2=${args2vs[@]}
        _log_para "$param2$"

        $bin1 "${args1vs[@]}" | $bin2 "${args2vs[@]}" 2> /tmp/ffmpeg-${streamid}.stderr &

        childpid=$!
        _log "${BLUE}CHILDPID = $childpid"
        wait $childpid

fi

if grep "Conversion failed!" /tmp/ffmpeg-${streamid}.stderr || grep "Unknown encoder" /tmp/ffmpeg-${streamid}.stderr || grep "not found for input stream" /tmp/ffmpeg-${streamid}.stderr || grep "Error opening filters!" /tmp/ffmpeg-${streamid}.stderr || grep "Unrecognized option" /tmp/ffmpeg-${streamid}.stderr || grep "Invalid data found when processing input" /tmp/ffmpeg-${streamid}.stderr && ! grep "Error writing trailer of pipe:" /tmp/ffmpeg-${streamid}.stderr; then

        _log "${BLUE}*** CHILD END ***"
        startexectime=`date +%s`
        _log "${BLUE}STDOUT   =${WHITE}"
        _log_para "`tail -n 18 /tmp/ffmpeg-${streamid}.stderr`"
        _log "${YELLOW}MODE     = WRAPPER_SINGLE-VS"
        _log "${BLUE}FFMPEG   = $bin2"
        _log "${GREEN}PARAM_WRAP   =${WHITE}"
        paramwps=${argsnew[@]}
        _log_para "$paramwps"

        $bin2 "${argsnew[@]}" 2> /tmp/ffmpeg-${streamid}.stderr &

        childpid=$!
        _log "${BLUE}CHILDPID = $childpid"
        wait $childpid

fi

stopexectime=`date +%s`
if test $((stopexectime-startexectime)) -lt 10; then
        _log "${BLUE}STDOUT   =${WHITE}"
        _log_para "${RED}`tail -n 22 /tmp/ffmpeg-${streamid}.stderr`${WHITE}"
        # _log_para "`cat /tmp/ffmpeg-${streamid}.stderr`"
fi

_log "${PURPLE}*** CHILD END ***"
_log "${PURPLE}*** PROCESS END ***"
newline
newline

rm -f /tmp/ffmpeg-${streamid}.stderr
exit 0
